package com.sl.biz.modular.job.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import com.sl.biz.domain.request.JobPageParamRpcRequest;
import com.sl.biz.modular.job.controller.request.JobAddRequest;
import com.sl.biz.modular.job.controller.request.JobGetByIdRequest;
import com.sl.biz.modular.job.controller.request.JobUpdateByIdRequest;
import com.sl.biz.modular.job.dao.entity.JobConfigDO;
import com.sl.biz.modular.job.dao.service.JobConfigDaoService;
import com.sl.biz.modular.job.service.JobConfigBizService;
import com.sl.biz.modular.process.controller.request.SquareLakeProcessRunRequest;
import com.sl.biz.modular.process.dao.domain.entity.ProcessRelationConfigDO;
import com.sl.biz.modular.process.service.ProcessRelationConfigBizService;
import com.sl.biz.modular.process.service.ProcessVersionContentBizService;
import com.sl.common.timer.CommonTimerTaskRunner;
import com.sl.core.engine.utils.TidUtil;
import com.sl.core.job.ProcessJobConfig;
import com.sl.core.job.enums.JobStateEnum;
import com.sl.core.job.scheduler.JobTask;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronTrigger;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
@Slf4j
@RequiredArgsConstructor
public class JobConfigBizServiceImpl implements JobConfigBizService {

    private final JobConfigDaoService jobConfigDaoService;

    private final ProcessRelationConfigBizService relationConfigBizService;

    private final ProcessVersionContentBizService processService;

    /**
     * 初始化加载定时任务
     */
    @InterceptorIgnore(tenantLine = "true")
    @Override
    public void init() {
        LambdaQueryWrapper<JobConfigDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(JobConfigDO::getState, JobStateEnum.JOB_RUN.getStatus(), JobStateEnum.JOB_STOP.getStatus());
        List<JobConfigDO> jobList = jobConfigDaoService.list(queryWrapper);
        jobList.forEach(quartzJob -> {
            CronTrigger cronTrigger = ProcessJobConfig.INSTANCE.getCronTrigger(quartzJob.getId());
            if (Objects.isNull(cronTrigger)) {
                ProcessJobConfig.INSTANCE.addJob(quartzJob.getId(),
                        quartzJob.getParams(), quartzJob.getCron(), quartzJob.getState());
            } else {
                ProcessJobConfig.INSTANCE.updateJob(quartzJob.getId(),
                        quartzJob.getCron(), quartzJob.getParams(), quartzJob.getState());
            }
        });
    }


    @Override
    public JobConfigDO getById(JobGetByIdRequest jobGetByIdRequest) {
        return jobConfigDaoService.getById(jobGetByIdRequest.getId());
    }

    @Transactional(rollbackOn = Exception.class)
    @Override
    public String add(JobAddRequest jobAddRequest) {
        JobConfigDO jobConfigDO = BeanUtil.copyProperties(jobAddRequest, JobConfigDO.class);
        String beanName = jobConfigDO.getBeanName();
        if (StrUtil.isBlank(beanName)) {
            jobConfigDO.setBeanName(JobTask.class.getName());
        }
        jobConfigDO.setState(JobStateEnum.JOB_STOP.getStatus());
        Boolean flag = jobConfigDaoService.save(jobConfigDO);
        if (flag) {
            ProcessJobConfig.INSTANCE.addJob(
                    jobConfigDO.getId(),
                    jobAddRequest.getParams(),
                    jobAddRequest.getCron(),
                    jobConfigDO.getState()
            );
        }
        return jobConfigDO.getId();
    }

    @Override
    public Boolean updateById(JobUpdateByIdRequest updateByIdRequest) {
        JobConfigDO jobConfigDO = BeanUtil.copyProperties(updateByIdRequest, JobConfigDO.class);
        JobConfigDO quartzJob = jobConfigDaoService.getById(jobConfigDO.getId());

        Boolean flag = jobConfigDaoService.updateById(jobConfigDO);
        if (flag) {
            ProcessJobConfig.INSTANCE.updateJob(updateByIdRequest.getId(),
                    jobConfigDO.getCron(), jobConfigDO.getParams(), quartzJob.getState());
        }
        return flag;
    }

    @Override
    public Boolean pause(String id) {
        JobConfigDO jobConfigDO = jobConfigDaoService.getById(id);
        if (!Objects.isNull(jobConfigDO)) {
            jobConfigDO.setState(JobStateEnum.JOB_STOP.getStatus());
            boolean b = jobConfigDaoService.updateById(jobConfigDO);
            if (b) {
                ProcessJobConfig.INSTANCE.checkStop(jobConfigDO.getId(),
                        jobConfigDO.getState());
            }
        }
        return true;
    }

    @Override
    public Boolean resume(String id) {
        JobConfigDO quartzJob = jobConfigDaoService.getById(id);
        if (!Objects.isNull(quartzJob)) {
            quartzJob.setState(JobStateEnum.JOB_RUN.getStatus());
            boolean b = jobConfigDaoService.updateById(quartzJob);
            if (b) {
                ProcessJobConfig.INSTANCE.resumeJob(id);
            }
        }
        return true;
    }

    @Override
    public Boolean runOnce(String id) {
        JobConfigDO quartzJob = jobConfigDaoService.getById(id);
        if (!Objects.isNull(quartzJob) && quartzJob.getState() != JobStateEnum.JOB_DEL.getStatus()) {
            ProcessJobConfig.INSTANCE.runOne(quartzJob.getId(), quartzJob.getParams());
        }
        return true;
    }

    @Override
    public List<JobConfigDO> list(JobConfigDO jobConfigDO) {
        LambdaQueryWrapper<JobConfigDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StrUtil.isNotBlank(jobConfigDO.getGroupId()), JobConfigDO::getGroupId,
                jobConfigDO.getGroupId());
        lambdaQueryWrapper.eq(StrUtil.isNotBlank(jobConfigDO.getGroupCode()), JobConfigDO::getGroupCode,
                jobConfigDO.getGroupCode());
        lambdaQueryWrapper.eq(StrUtil.isNotBlank(jobConfigDO.getProductId()), JobConfigDO::getProductId,
                jobConfigDO.getProductId());
        List<JobConfigDO> list = jobConfigDaoService.list(lambdaQueryWrapper);
        return list;
    }

    @Override
    public List<JobConfigDO> page(JobPageParamRpcRequest jobPageParamRpcRequest) {
        List<JobConfigDO> jbList = jobConfigDaoService.queryList(jobPageParamRpcRequest);
        return jbList;
    }

    @Override
    public Boolean remoteById(String id) {
        JobConfigDO quartzJob = jobConfigDaoService.getById(id);
        ProcessJobConfig.INSTANCE.remove(quartzJob.getId());
        return jobConfigDaoService.removeById(id);
    }

    @Override
    public Boolean run(String id) {
        return this.resume(id);
    }

    @Override
    public Date nextFireTime(String id) {
        return ProcessJobConfig.INSTANCE.nextFireTime(id);
    }

    @InterceptorIgnore(tenantLine = "true")
    @Override
    public Object execute(String jobId) {
        String tid = TidUtil.getTid();
        JobConfigDO quartzJob = jobConfigDaoService.getById(jobId);

        if (ObjectUtil.isNull(quartzJob)) {
            return null;
        }

        //找到关联的流程
        List<ProcessRelationConfigDO> processRelationConfigDOS = relationConfigBizService.queryByBizIdAndBizType(jobId, "JOB");
        if (CollUtil.isEmpty(processRelationConfigDOS)) {
            String beanName = quartzJob.getBeanName();
            String params = quartzJob.getParams();
            CommonTimerTaskRunner bean = null;
            try {
                bean = SpringUtil.getBean(beanName);
            } catch (Exception e) {
                log.error("获取bean失败", e);
            }
            if (ObjectUtil.isNotNull(bean)) {
                bean.action(params);
            }
            return null;
        }
        List<Object> result = Lists.newArrayList();
        for (ProcessRelationConfigDO processRelationConfigDO : processRelationConfigDOS) {
            //接收到消息 需要驱动
            SquareLakeProcessRunRequest runRequest = new SquareLakeProcessRunRequest();
            runRequest.setProcessId(processRelationConfigDO.getProcessId());
            runRequest.setParam(processRelationConfigDO.getParams());
            runRequest.setTid(tid);
            runRequest.setProcessVersion(processRelationConfigDO.getProcessVersion());
            Object run = processService.run(runRequest);
            result.add(run);
        }
        return CollUtil.size(result) == 1 ? CollUtil.get(result, 0) : result;
    }

    @Override
    public boolean count(String beanName, String cron, String excludeId) {

        return jobConfigDaoService.count(new LambdaQueryWrapper<JobConfigDO>()
                .eq(JobConfigDO::getBeanName, beanName)
                .eq(JobConfigDO::getCron, cron)
                .ne(StrUtil.isNotBlank(excludeId), JobConfigDO::getId, excludeId)
        ) > 0;
    }
}
